﻿//    Copyright 2014 LuoZhihui
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//      http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

#region  导入名称空间

using System;
using System.Collections.Generic;
using System.Linq;
using LotteryEngine.Infrastructure.Querying;
using LotteryEngine.Infrastructure.UnitOfWork;
using LotteryEngine.Model.Repositories;

#endregion

namespace LotteryEngine.Model.Services
{
	public class ConfigService
	{
		/// <summary>
		///     未中奖平衡值（这个是基本算子，只要大于0就可以）
		/// </summary>
		private const int ProportionNotWin = 1;

		private readonly IConfigRepository _configRepository;
		private readonly IPrizeRepository _prizeRepository;
		private readonly ISweepstakeRepository _sweepstakeRepository;
		private readonly IUnitOfWork _unitOfWork;


		public ConfigService(
			ISweepstakeRepository sweepstakeRepository,
			IPrizeRepository prizeRepository,
			IConfigRepository configRepository,
			IUnitOfWork unitOfWork)
		{
			_sweepstakeRepository = sweepstakeRepository;
			_prizeRepository = prizeRepository;
			_configRepository = configRepository;
			_unitOfWork = unitOfWork;
		}


		/// <summary>
		///     刷新活动配置
		/// </summary>
		public void RefreshConfig(Sweepstake sweepstake)
		{
			var query = new Query();
			query.Add(Criterion.Create<Config>(cfg => cfg.Sweepstake.Id, sweepstake.Id, CriteriaOperator.Eq));

			var allPrizeConfig = _configRepository.FindBy(query);

			foreach (var item in allPrizeConfig)
			{
				//开始日期小于或等于今天
				var startDateLesserOrEqualThanToday = DateTime.Compare(item.StartDate, DateTime.Today) < 1;
				//结束日期大于或等于今天
				var endDateGreaterOrEqualThanToday = DateTime.Compare(item.EndDate, DateTime.Today) > -1;

				item.IsActived = startDateLesserOrEqualThanToday && endDateGreaterOrEqualThanToday;

				_configRepository.Save(item);
			}
			_unitOfWork.Commit();
		}


		/// <summary>
		///     活动控制
		/// </summary>
		/// <param name="sweepstake"></param>
		/// <param name="init"></param>
		private void SweepstakesControl(Sweepstake sweepstake, bool init)
		{
			var prizeConfigs = sweepstake.Configs;
			foreach (var prizeConfig in prizeConfigs)
			{
				if (sweepstake.IsActived)
				{
					prizeConfig.IsActived = true;
					prizeConfig.Prize.IsActived = true;
				}
				else
				{
					prizeConfig.IsActived = false;
					prizeConfig.Prize.IsActived = false;
				}

				if (init)
				{
					prizeConfig.PrizeBlance = prizeConfig.LotteryCount;
					prizeConfig.Prize.PrizeBlance = prizeConfig.Prize.TotalCount;
				}

				_prizeRepository.Save(prizeConfig.Prize);
				_configRepository.Save(prizeConfig);
			}
		}

		/// <summary>
		///     计算各奖项平衡值
		///     公式  该奖项平衡值=  开出轮空项概率系数/该奖项的中奖概率系数 * 轮空项的平衡值
		/// </summary>
		/// <param name="cfgItem"></param>
		/// <param name="doNotWin"></param>
		/// <returns></returns>
		private double CalcProportion(Config cfgItem, Config doNotWin)
		{
			return doNotWin.OddsCoefficient/cfgItem.OddsCoefficient*doNotWin.Proportion;
		}

		/// <summary>
		///     自动平衡各个奖项的概率
		///     <remarks>建立圆桌算法，保证任意一奖项概率提高时自动压缩其余奖项开出概率，使总概率保持为1 </remarks>
		/// </summary>
		public List<Config> AutomaticBalanceTotalProbability(IEnumerable<Config> lotteryConfigs)
		{
			var configItems = lotteryConfigs as Config[] ?? lotteryConfigs.ToArray();
			var configList = configItems.ToList();

			var doNotWin = configList.Find(x => x.IsByeItem);
			doNotWin.Proportion = ProportionNotWin;

			foreach (var item in configList.Where(item => !item.IsByeItem))
			{
				item.Proportion = CalcProportion(item, doNotWin);
			}

			//计算平衡值之和
			var sumProportion = configList.Sum(x => x.Proportion);

			//计算概率
			//公式 该奖项概率=该奖项平衡值/平衡值之和
			configList.ForEach(configItem =>
			{
				configItem.Probability = configItem.Proportion/sumProportion;
				_configRepository.Save(configItem);
			});

			_unitOfWork.Commit();

			return configList;
		}

		private static string GenerateGroupedKey(Sweepstake sweepstake, Config config)
		{
			var startStr = config.StartDate.ToString("yyyyMMdd");
			var endStr = config.EndDate.ToString("yyyyMMdd");


			return string.Format("{0}_{1}_{2}", sweepstake.Code, startStr, endStr);
		}


		/// <summary>
		///     刷新各个活动赔率 init=true 初始化抽奖（奖品剩余数量复位） init=false 仅重新计算中奖概率
		/// </summary>
		public void RefreshLotteryConfig(bool init = false)
		{
			var sweepstakes = _sweepstakeRepository.FindAll();
			var validSweepstakes = sweepstakes.Where(sweepstake => sweepstake.IsActived && sweepstake.Configs.Any());
			foreach (var sweepstake in validSweepstakes)
			{
				SweepstakesControl(sweepstake, init);
				var groupedCfgs = sweepstake.Configs.GroupBy(x => GenerateGroupedKey(sweepstake, x));

				foreach (var cfgs in groupedCfgs)
				{
					var balancedConfigs = AutomaticBalanceTotalProbability(cfgs.ToList());

					foreach (var cfg in balancedConfigs.Where(cfg => init))
					{
						cfg.PrizeBlance = cfg.LotteryCount;
						cfg.Prize.PrizeBlance = cfg.Prize.TotalCount;
						_prizeRepository.Save(cfg.Prize);
						_configRepository.Save(cfg);
					}
				}
			}

			_unitOfWork.Commit();
		}
	}
}